﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Transcend.Utility;
using System.Net.FtpClient;
using Transcend.Archive.CSScan.Store.Contract;

namespace Transcend.Archive.CSScan.Stores
{
    /// <summary>
    /// Ftp图像存储
    /// </summary>
    public class FTPImageStore : Transcend.Archive.CSScan.Store.Contract.ImageStore
    {
        /// <summary>
        /// 构造器
        /// </summary>
        public FTPImageStore() : base(0M) { }

        private static readonly log4net.ILog logger = log4net.LogManager.GetLogger(typeof(FTPImageStore));
        /// <summary>
        /// 构造器
        /// </summary>
        /// <param name="storeId">存储Id</param>
        public FTPImageStore(decimal storeId) : base(storeId) { }

        FTPStoreDescript desc = null;

        System.Data.Common.DbConnection conn = null;


        /// <summary>
        /// 分析存储描述信息
        /// </summary>
        /// <param name="Descripts"></param>
        public override void Parse(string Descripts)
        {
            desc = Newtonsoft.Json.JsonConvert.DeserializeObject<FTPStoreDescript>(Descripts);
            if (string.IsNullOrEmpty(desc.ServerAddr))
            {
                throw new ArgumentException("FTP服务器地址没有设置");
            }

            if (desc.Port < 1) desc.Port = 21;
            if (string.IsNullOrEmpty(desc.Encoding))
            {
                desc.Encoding = "utf-8";
            }

            var connString = desc.ConnectionString;
            if (connString.IndexOf("provider") == 0 && connString.IndexOf("Provider") == 0)
            {
                if (!connString.EndsWith(";")) connString += ";";
                connString += "provider=" + desc.Provider;
            }
            conn = Transcend.Utility.Db.GetConnection(desc.ConnectionString + ";provider=" + desc.Provider);
            if (conn.State != System.Data.ConnectionState.Open) conn.Open();
        }
        /// <summary>
        /// 保存到Ftp
        /// </summary>
        public override void Save()
        {

            foreach (var group in _images.GroupBy(it => it.InstanceId))     //按实例分组，因为每个实例可能存放的路径不一样
            {
                var path = string.Empty;
                var ftp = GetFtp();
                if (ftp == null)
                {
                    throw new Exception(string.Format("不能正确连接到Ftp服务器:ftp://{0}:{1}@{2}", desc.User, desc.Password, desc.ServerAddr));
                }
                using (ftp)
                {
                    foreach (var img in group)  //处理每个实例下的图像
                    {
                        if (string.IsNullOrEmpty(path))
                        {
                            path = BuildSavePath(img);   //获取路径
                            cwd(ftp, path);   //进入目录
                        }
                        AppendFile(ftp, img, path);       //将图像保存到服务器
                        logger.Debug(string.Format("原文已保存到：{0}/{1}", path, img.FileName));
                    }
                }
            }
        }


        /// <summary>
        /// 获取保存路径
        /// </summary>
        /// <param name="img">图形</param>
        /// <returns></returns>
        private string BuildSavePath(Store.Contract.ScanImage img)
        {
            #region 确定宗下是否上传过图像，如果上传过，则用原来的路径
            string sql = "Select folder  from DS_INSTANCE i,DS_ITEM t, DS_PAGE p where i.ID=t.INST_ID and t.ID=p.item_id and  p.id={0}";
            string path = Db.ExecuteScaler<string>(conn, sql, img.ImageNo);
            if (!string.IsNullOrEmpty(path))
            {
                return path;
            }
            #endregion

            //生成路径
            var macroPath = desc.SavePathMacro;
            using (var cmd = conn.CreateCommand())
            {
                foreach (var item in desc.DataSources)
                {
                    //替换Sql中的变量，使其能够查询相应的位置

                    sql = item.Value.Format<Transcend.Archive.CSScan.Store.Contract.ScanImage>(img, "Image", "null");
                    cmd.CommandText = sql;
                    using (var reader = cmd.ExecuteReader())
                    {
                        if (reader.Read())
                        {
                            string pattern = "\\{" + item.Key + "\\.([^}]+)\\}";
                            System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex(pattern);

                            Func<System.Text.RegularExpressions.Match, string> replacer = (match) =>
                            {
                                string key = match.Groups[1].Value.Trim();
                                string val = "";
                                val = Db.GetValue<string>(reader, key);
                                if (Db.IsNull(val))
                                {
                                    val = "空";
                                }
                                return val;
                            };
                            macroPath = reg.Replace(macroPath, new System.Text.RegularExpressions.MatchEvaluator(replacer));
                        }
                    }
                }

                #region 将保存路径更新到宗实例上
                sql = "update DS_INSTANCE d set d.folder={0} where d.ID in (select t.INST_ID from DS_ITEM t,DS_PAGE p where p.item_id=t.ID and p.ID={1})";
                Db.InitCommand(cmd, sql, macroPath, img.ImageNo);
                cmd.ExecuteNonQuery();
                #endregion

            }

            return macroPath.Macro("空");
        }
        /// <summary>
        /// 获取图形
        /// </summary>
        /// <param name="uri">统一定位符</param>
        /// <param name="filename">文件名</param>
        /// <returns>返回图像字节数据</returns>
        public byte[] GetImage(string uri, string filename)
        {

            var ftp = GetFtp();
            if (ftp == null)
            {
                throw new Exception(string.Format("不能正确连接到Ftp服务器:ftp://{0}:{1}@{2}", desc.User, desc.Password, desc.ServerAddr));
            }
            using (ftp)
            {
                try
                {
                    cwd(ftp, uri);
                    using (var stream = ftp.OpenRead(filename))
                    {
                        /*
                        byte[] buffer = new byte[stream.Length];
                        stream.Read(buffer, 0, buffer.Length);
                        return buffer;
                        */
                        var readLength = 64000;
                        var contentLength = 0;
                        byte[] buffer = new byte[readLength];
                        var result = new System.IO.MemoryStream();
                        do
                        {
                            contentLength = stream.Read(buffer, 0, readLength);
                            result.Write(buffer, 0, contentLength);

                        } while (stream.Position < stream.Length - 1);
                        return result.ToArray();
                    }
                }
                catch (Exception e) {
                    return new byte[0];
                }
            }
        }

        /// <summary>
        /// 获取图像
        /// </summary>
        /// <param name="instid">实例Id</param>
        /// <param name="imgNo">图形Id</param>
        /// <returns>返回图像字节数据</returns>
        public override byte[] GetImage(decimal instid, decimal imgNo)
        {
            var sql = "select RAW_FILE_NAME,(select folder from ds_instance where ID=(select inst_id from ds_item b where b.ID=a.item_id)) folder from ds_page a where ID={0}";
            var uri = string.Empty;
            var filename = string.Empty;

            using (var cmd = conn.CreateCommand())
            {
                Transcend.Utility.Db.InitCommand(cmd, sql, imgNo);
                using (var dr = cmd.ExecuteReader())
                {
                    if (!dr.Read())
                    {
                        throw new ArgumentException(string.Format("档案原文不存在imgno={0}", imgNo));
                    }
                    uri = Transcend.Utility.Db.GetValue<string>(dr, "folder");
                    filename = Transcend.Utility.Db.GetValue<string>(dr, "RAW_FILE_NAME");
                }
            }
            return GetImage(uri, filename);
        }
        /// <summary>
        /// 从服务器删除一个图像
        /// </summary>
        /// <param name="instanceId">实例Id</param>
        /// <param name="imageNo">图形Id</param>
        /// <returns>图形Id</returns>
        public override int Delete(decimal instanceId, decimal imageNo)
        {
            //return 1;
            string path = Db.ExecuteScaler<string>(conn, "select FOLDER from DS_INSTANCE where ID={0}", instanceId);
            if (string.IsNullOrEmpty(path))
            {
                return 0;
                //throw new Exception("实例没保存图像，不能删除图像。");
            }
            string fileName = Db.ExecuteScaler<string>(conn, "select RAW_FILE_NAME from DS_PAGE where ID={0}", imageNo);
            if (string.IsNullOrEmpty(fileName))
            {
                throw new Exception("图像没保存到服务器，不能删除图像。");
            }
            //using (var ftp = new Limilabs.FTP.Client.Ftp())
            //{

            //    logger.Debug(string.Format("连接到:ftp://{0}:{1}@{2}", desc.User, "*", desc.ServerAddr));
            //    ftp.Connect(desc.ServerAddr, desc.Port);
            //    ftp.Login(desc.User, desc.Password);
            //    logger.Debug("登录成功");
            //    ftp.Mode = Limilabs.FTP.Client.FtpMode.Passive;
            //    cwd(ftp, path);
            //    ftp.DeleteFile(fileName);
            //}
            var ftp = GetFtp();
            if (ftp == null)
            {
                throw new Exception(string.Format("不能正确连接到Ftp服务器:ftp://{0}:{1}@{2}", desc.User, desc.Password, desc.ServerAddr));
            }
            using (ftp)
            {

                cwd(ftp, path);
                if (ftp.FileExists(fileName)) ftp.DeleteFile(fileName);
            }
            return 1;
        }

        /// <summary>
        /// 转到FTP目录
        /// </summary>
        public static void cwd(FtpClient ftp, string path)
        {
            var dir = path.Split(new char[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var d in dir)
            {

                if (ftp.DirectoryExists(d))
                {
                    //ftp.ChangeFolder(d);
                    ftp.SetWorkingDirectory(d);
                }
                else
                {
                    ftp.CreateDirectory(d);
                    ftp.SetWorkingDirectory(d);
                }
            }
            
        }
        /// <summary>
        /// 释放资源
        /// </summary>
        public override void Dispose()
        {
            base.Dispose();
            if (conn != null)
            {
                conn.Close();
            }
        }

        private FtpClient GetFtp()
        {
            var ftp = new FtpClient();
            
            logger.Debug(string.Format("连接到:ftp://{0}:{1}@{2}", desc.User, "*", desc.ServerAddr));
            //ftp.Connect(desc.ServerAddr, desc.Port);
            ftp.Host = desc.ServerAddr;
            ftp.Port = desc.Port;

            if (!string.IsNullOrEmpty(desc.User))
            {
                ftp.Credentials = new System.Net.NetworkCredential(desc.User, desc.Password);
            }
            try
            {
                ftp.Connect();
            }
            catch (ObjectDisposedException e)
            {
                logger.Debug("登录失败，" + e.Message);
                if (!ftp.IsDisposed) ftp.Dispose();
                return null;
            }
            catch (Exception e)
            {
                logger.Debug("登录失败，" + e.Message);
                if (!ftp.IsDisposed) ftp.Dispose();
                return null;
            }
            logger.Debug("登录成功");
            if (!string.IsNullOrEmpty(desc.Encoding))
            {
                ftp.Encoding = System.Text.Encoding.GetEncoding(desc.Encoding);
            }
            else {
                ftp.Encoding = System.Text.Encoding.Unicode;
            }
            ftp.DataConnectionType = FtpDataConnectionType.AutoPassive;
            return ftp;
        }

        private void AppendFile(FtpClient ftp, ScanImage img, string path)
        {
            string fullName = path.Replace('\\', '/');
            if (!fullName.EndsWith("/")) fullName += "/";
            if (!fullName.StartsWith("/")) fullName = "/" + fullName;
            fullName += img.FileName;
            ftp.SetWorkingDirectory("/");

            if (ftp.FileExists(fullName))
            {
                ftp.DeleteFile(fullName);
            }

            try
            {
                
                using (var ftpStream = ftp.OpenAppend(fullName, FtpDataType.Binary))
                {
                    ftpStream.Write(img.Content, 0, img.Content.Length);
                    ftpStream.Flush();
                    ftpStream.Close();
                }
            }
            catch (Exception e) {
                cwd(ftp, path);
                using (var ftpStream = ftp.OpenAppend(img.FileName, FtpDataType.Binary))
                {
                    ftpStream.Write(img.Content, 0, img.Content.Length);
                    ftpStream.Flush();
                    ftpStream.Close();
                }
            }
            using (var cmd = conn.CreateCommand())
            {
                //重新文件长度
                string sql = "update DS_PAGE set IMAGE_SIZE={0} where ID={1}";
                Db.InitCommand(cmd, sql, img.Content.Length, img.ImageNo);
                cmd.ExecuteNonQuery();
            }
        }

        /// <summary>
        /// 文件更名
        /// </summary>
        /// <param name="img">图形描述</param>
        public override void ChangeFileName(ScanImage img)
        {
            ScanImageDetail page = null;
            if ((img is ScanImageDetail))
            {
                page = (ScanImageDetail)img;
            }
            else
            {
                if (img.Tag != null && img.Tag is ScanImageDetail)
                {
                    page = img.Tag as ScanImageDetail;
                }
            }
            if (page == null)
            {
                throw new Exception("文件更名需要图像的详细信息。");
            }
            string fileName = GetFileName(page);
            fileName += System.IO.Path.GetExtension(page.FileName);                            //保持原来的扩展名
            using (var cmd = conn.CreateCommand())
            {
                using (var trans = conn.BeginTransaction())
                {
                    string sql = "select folder from DS_INSTANCE where ID={0}";
                    string folder = Db.ExecuteScaler<string>(conn, sql, page.InstanceId);
                    if (string.IsNullOrEmpty(folder)) throw new Exception("无效的实例，找不到图形存在路径。");
                    try
                    {
                        sql = "Update DS_PAGE p set p.RAW_FILE_NAME={0} where p.ID={1}";
                        Db.InitCommand(cmd, sql, fileName, page.ImageNo);
                        cmd.Transaction = trans;
                        cmd.ExecuteNonQuery();   //更新文件名

                        if (!folder.EndsWith("/")) folder += "/";
                        using (var ftp = GetFtp())
                        {

                            ftp.Rename(folder + page.FileName, folder + fileName);
                            page.FileName = fileName;
                            ftp.Disconnect();
                        }
                        trans.Commit();
                    }
                    catch
                    {
                        trans.Rollback();
                        throw;
                    }

                }
            }

        }



        public override void ChangeFileName(decimal imageNo, string newName)
        {
            //throw new NotImplementedException();
            using (var cmd = conn.CreateCommand())
            {
                using (var trans = conn.BeginTransaction())
                {
                    string sql = "select INST_ID from DS_ITEM i,ds_page p where p.item_id=i.ID and p.ID={0}";
                    var instId = Db.ExecuteScaler<decimal>(conn, sql, imageNo);
                    if (instId == 0) throw new Exception("无效的图形编号，找不到相应存储实例。");
                    sql = "select folder from DS_INSTANCE where ID={0}";
                    string folder = Db.ExecuteScaler<string>(conn, sql, instId);
                    if (string.IsNullOrEmpty(folder)) throw new Exception("无效的实例，找不到图形存在路径。");
                    sql = "select RAW_FILE_NAME from ds_page where ID={0}";
                    string oldName = Db.ExecuteScaler<string>(conn, sql, imageNo);
                    if (string.IsNullOrEmpty(oldName)) throw new Exception("无效的图形，找不到找不到图形对应的文件名称。");
                    
                    try
                    {
                        sql = "Update ds_page p set p.RAW_FILE_NAME={0} where p.ID={1}";
                        Db.InitCommand(cmd, sql, newName, imageNo);
                        cmd.Transaction = trans;
                        cmd.ExecuteNonQuery();   //更新文件名

                        if (!folder.EndsWith("/")) folder += "/";
                        using (var ftp = GetFtp())
                        {

                            ftp.Rename(folder + oldName, folder + newName);                            
                            ftp.Disconnect();
                        }
                        trans.Commit();
                    }
                    catch
                    {
                        trans.Rollback();
                        throw;
                    }

                }
            }
        }
    }
}
